#pragma once
#ifndef __LIT__MOVABLE__DATAS__INCLUDED__HH__
#define __LIT__MOVABLE__DATAS__INCLUDED__HH__

#include <LitPrerequisites.h>
#include <LitPointer.hpp>
#include <boost\any.hpp>

namespace Lit
{
	class LIT_API MovableDatas
	{
	public:
		typedef boost::any									Any;
		typedef std::map<std::string, Any>					Map;
		typedef std::map<std::string, Any>::iterator		Itor;
		typedef std::map<std::string, Any>::const_iterator	ConstItor;

	protected:
		Map map;
		std::string movable_name;

	public:
		MovableDatas( const std::string & parent_ );
		MovableDatas( const MovableDatas& rk );
		~MovableDatas( );

		bool hasData( const std::string &name ) const;
		void addData( const std::string &name, Any any );

		std::string propertyFullName( const std::string &name ) const;

		template<typename T>
		void setData( const std::string &name, T& var )
		{
			map[name] = boost::any(var);
		}
		template<typename T>
		void setData( const std::string &name, const T& var )
		{
			map[name] = boost::any(var);
		}
		template<typename T>
		void setData( const std::string &name, T* var )
		{
			map[name] = boost::any( var );
		}
		template<typename T>
		void setData( const std::string &name, const T* var )
		{
			map[name] = boost::any( var );
		}
		
		template<typename ReturnType>
		ReturnType* getData( const std::string &name, ReturnType * defaultVal, bool except )
		{
			if( !hasData( name ) ) throw Lit::ItemMissing( propertyFullName(name), "MovableDatas("+movable_name+")", EXC_LOC );
			Itor i = map.find(name);
			try{ return boost::any_cast<ReturnType>( &i->second ); }
			catch( ... ){ if( except ) throw Lit::CastError( propertyFullName(name), typeid((*i)).name(), typeid(defaultVal).name(), EXC_LOC ); }
			return defaultVal;
		}
		template<typename ReturnType>
		const ReturnType* getData( const std::string &name, const ReturnType * defaultVal, bool except ) const
		{
			if( !hasData( name ) ) throw Lit::ItemMissing( propertyFullName(name), "MovableDatas("+movable_name+")", EXC_LOC );
			ConstItor i = map.find(name);
			try{ return boost::any_cast<ReturnType>( &i->second ); }
			catch( ... ){ if( except ) throw Lit::CastError( propertyFullName(name), typeid((*i)).name(), typeid(defaultVal).name(), EXC_LOC ); }
			return defaultVal;
		}
		template<typename ReturnType>
		ReturnType getData( const std::string &name, const ReturnType& defaultVal, bool except ) const
		{
			if( !hasData( name ) ) throw Lit::ItemMissing( propertyFullName(name), "MovableDatas("+movable_name+")", EXC_LOC );
			ReturnType ret;
			ConstItor i = map.find(name);
			try{ return boost::any_cast<ReturnType>( i->second ); }
			catch( ... ){ if( except ) throw Lit::CastError( propertyFullName(name), typeid((*i)).name(), typeid(defaultVal).name(), EXC_LOC ); }
			return defaultVal;
		}

		size_t size() const;
		bool empty() const;
		void clear();

		std::string parentName() const;
		
		const Map & datas() const;
		Map& datas();

		Itor begin();
		ConstItor begin() const;

		Itor end();
		ConstItor end() const;
	}; 
};

#endif